#include <ProcessComposition.h>
#include <ProcessStats.h>
#include <csp_debug.h>
#include <csp_macros.h>
#include <csp_shared_types.h>
#include <csp_protocol_msg.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <pthread.h>
#include <map>
#include <vector>

using namespace std;


bool ProcessStats::CheckTerminationValues()
{
	bool res = true;

	pair<ProcessComposition*, int> *pr;
	for(unsigned int i = 0; i < process_vector.size(); i++){
		pr = process_vector.at(i);
		if(pr->second != pr->first->GetExitStatus()){
			res = false;
			printf("Expected result (%i) from process (pid=%i, code=%s, state=%x) "
				   "did not equal actual result (%i)\n", 
			pr->second, 
			pr->first->GetPID(), pr->first->GetMnemonic(), pr->first->GetState(),
			pr->first->GetExitStatus());
		}
	}

	return res;
}



bool ProcessStats::CheckNumberOfTerminatedProcesses()
{
	int stateTerminated = 0;
	
	pair<ProcessComposition*, int> *pr;
	for(unsigned int i = 0; i < process_vector.size(); i++){
		pr = process_vector.at(i);
		if(STATE_EXIT == pr->first->GetState()){
			stateTerminated++;
		}
	}

	bool sTerm  = (stateTerminated == (int)process_vector.size() && process_vector.size() );
	bool pCount = (p_count == (int)process_vector.size());

	if( !sTerm ){
		printf("!! Only %i processes had state STATE_EXIT out of %i processes.\n", 
			stateTerminated, process_vector.size() );
	}


	if( !pCount ){
		printf("!! Mismatch between expected number of processes (%i) and "
			   "executed processes (%i)\n", p_count, process_vector.size());	
	}

	return sTerm && pCount ;
}


void ProcessStats::Check()
{
		if( !CheckTerminationValues() ){
			printf("!! Test of termination values failed.\n");	
		}
		if( !CheckNumberOfTerminatedProcesses() ){
			printf("!! Test of number of terminated processes failed.\n");	
		}
		if( !CheckPids() ){
			printf("!! Test of unique pids failed.\n");	
		}
}

bool ProcessStats::CheckPids()
{
	bool res = true;


	int pid_count = process_vector.size();
	int pids[pid_count]; memset(pids, 0, sizeof(int)*pid_count);

	if( !pid_count ){
		res = false;	
		printf("!! No processes available.\n");
	}

	pair<ProcessComposition*, int> *pr;
	int idx;
	for(unsigned int i = 0; i < process_vector.size(); i++){
		pr = process_vector.at(i);
		idx = pr->first->GetPID() - 100; /* pidcount start at 100*/
		if(idx < 0 || idx >= pid_count){
			printf("!! Encountered weird pid %i\n", idx+100);	
			res = false;
		}
		pids[i] = idx;
	}

	for(int i = 0; i < pid_count; i++){
		if(pids[i] != i){
			printf("!! Not all pids were unique, did not found pid "
			"with number %i out of %i pids\n", i, pid_count);
			res =  false;
		}	
	}

	return res;
}


ProcessStats::ProcessStats()
{
	pthread_mutex_init(&lock, NULL);

}

ProcessStats::~ProcessStats()
{
}

void 
ProcessStats::RegisterExpectedRes(ProcessComposition *p, int exp_res)
{
	pthread_mutex_lock(&lock);

	process_vector.push_back(new pair<ProcessComposition*, int>(p, exp_res));

	pthread_mutex_unlock(&lock);
}

ProcessStats* ProcessStats::pinstance = 0;// initialize pointer

	ProcessStats* 
ProcessStats::Instance () 
{
	if (pinstance == 0)  // is it the first call?
	{  
		pinstance = new ProcessStats(); // create sole instance
	}
	return pinstance; // address of sole instance
}


